# -*- coding:utf-8 -*-

"""
黑名单服务 - 用于过滤搜索结果
"""

import re
from typing import List, Dict, Any, Optional
from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession

from module_admin.entity.do.seller_blacklist_do import SellerBlacklist
from module_admin.entity.do.title_blacklist_do import TitleBlacklist
from module_admin.entity.do.search_record_do import SearchRecord
from utils.log_util import logger


class BlacklistService:
    """黑名单服务"""
    
    @classmethod
    async def get_seller_blacklist(cls, db: AsyncSession, user_id: Optional[int] = None) -> List[Dict[str, Any]]:
        """
        获取商家黑名单列表（按用户隔离）
        
        Args:
            db: 数据库会话
            user_id: 用户ID，如果提供则只获取该用户的黑名单
        
        Returns:
            [{'seller_id': 'xxx', 'seller_nick': 'xxx'}, ...]
        """
        query = select(SellerBlacklist).where(
            SellerBlacklist.del_flag == '0',
            SellerBlacklist.status == '0'  # ✅ 只获取启用状态的黑名单
        )
        
        # ✅ 用户隔离：只获取当前用户的黑名单
        if user_id is not None:
            query = query.where(SellerBlacklist.create_by == str(user_id))
        
        result = await db.execute(query)
        blacklist = result.scalars().all()
        
        return [
            {
                'seller_id': item.seller_id,
                'seller_nick': item.seller_nick
            }
            for item in blacklist
        ]
    
    @classmethod
    async def get_title_blacklist(cls, db: AsyncSession, user_id: Optional[int] = None) -> List[Dict[str, Any]]:
        """
        获取商品标题黑名单列表（按用户隔离）
        
        Args:
            db: 数据库会话
            user_id: 用户ID，如果提供则只获取该用户的黑名单
        
        Returns:
            [{'keyword': 'xxx', 'match_type': 'contains'}, ...]
        """
        query = select(TitleBlacklist).where(
            TitleBlacklist.del_flag == '0',
            TitleBlacklist.status == '0'  # ✅ 只获取启用状态的黑名单
        )
        
        # ✅ 用户隔离：只获取当前用户的黑名单
        if user_id is not None:
            query = query.where(TitleBlacklist.create_by == str(user_id))
        
        result = await db.execute(query)
        blacklist = result.scalars().all()
        
        return [
            {
                'keyword': item.keyword,
                'match_type': item.match_type or 'contains'
            }
            for item in blacklist
        ]
    
    @classmethod
    async def filter_search_results(
        cls,
        db: AsyncSession,
        search_results: List[Dict[str, Any]],
        user_id: Optional[int] = None  # ✅ 新增：用户ID（用于黑名单隔离）
    ) -> List[Dict[str, Any]]:
        """
        过滤搜索结果（移除黑名单商品，按用户隔离）
        
        Args:
            db: 数据库会话
            search_results: 搜索结果列表
            user_id: 用户ID，用于获取该用户的黑名单
            
        Returns:
            过滤后的搜索结果
        """
        if not search_results:
            return []
        
        # ✅ 获取当前用户的黑名单（用户隔离）
        seller_blacklist = await cls.get_seller_blacklist(db, user_id=user_id)
        title_blacklist = await cls.get_title_blacklist(db, user_id=user_id)
        
        
        filtered_results = []
        filtered_count = 0
        
        for item in search_results:
            # 检查商家黑名单
            if cls._is_seller_blacklisted(item, seller_blacklist):
                filtered_count += 1
                # ✅ 移除详细日志，避免日志太乱（只保留汇总日志）
                continue
            
            # 检查标题黑名单
            if cls._is_title_blacklisted(item, title_blacklist):
                filtered_count += 1
                # ✅ 移除详细日志，避免日志太乱（只保留汇总日志）
                continue
            
            # 通过过滤
            filtered_results.append(item)
        
        # ✅ 记录过滤日志（只在有过滤时输出）
        if filtered_count > 0:
            logger.info(f"黑名单过滤: 原始{len(search_results)}个商品，过滤{filtered_count}个，剩余{len(filtered_results)}个")
        
        return filtered_results
    
    @classmethod
    def _is_seller_blacklisted(
        cls,
        item: Dict[str, Any],
        seller_blacklist: List[Dict[str, Any]]
    ) -> bool:
        """
        检查商家是否在黑名单中
        
        ✅ 匹配规则（ID和昵称是"或"的关系，但优先级不同）：
        1. seller_id：完整匹配（精确匹配）- 优先使用，精准过滤
           - 如果黑名单有seller_id，优先用seller_id匹配
           - 如果seller_id匹配成功，返回True（过滤）
           - 如果seller_id不匹配，跳过该条黑名单记录（不检查seller_nick，避免误匹配）
        2. seller_nick：包含匹配或完整匹配（仅当黑名单没有seller_id时使用）
           - 包含匹配：黑名单昵称在商品昵称中
           - 完整匹配：完全相等
        
        总结：ID和昵称是"或"的关系（满足任一条件即过滤），但有优先级：
        - 如果黑名单有ID，只看ID匹配（精准）
        - 如果黑名单没有ID，才看昵称匹配（宽松）
        """
        item_seller_id = str(item.get('seller_id') or item.get('sellerId') or '').strip()
        item_seller_nick = str(item.get('seller_nick') or item.get('sellerNick') or '').strip()
        
        for blacklisted in seller_blacklist:
            blacklisted_seller_id = str(blacklisted.get('seller_id') or '').strip()
            blacklisted_seller_nick = str(blacklisted.get('seller_nick') or '').strip()
            
            # ✅ 规则1：seller_id 完整匹配（精确匹配）- 优先使用，精准过滤
            # 如果黑名单有seller_id，优先使用seller_id匹配（最精准）
            if blacklisted_seller_id:
                if item_seller_id and item_seller_id == blacklisted_seller_id:
                    return True
                # ✅ 如果黑名单有seller_id，但商品seller_id不匹配，则不使用seller_nick匹配（避免误匹配）
                # 例如：黑名单seller_id="1", seller_nick="A"，商品seller_id="2", seller_nick="A" 不应该匹配
                continue
            
            # ✅ 规则2：seller_nick 包含匹配或完整匹配（仅当黑名单没有seller_id时使用）
            if blacklisted_seller_nick and item_seller_nick:
                # 包含匹配：黑名单昵称在商品昵称中
                if blacklisted_seller_nick in item_seller_nick:
                    return True
                # 完整匹配：完全相等
                if item_seller_nick == blacklisted_seller_nick:
                    return True
        return False
    
    @classmethod
    def _is_title_blacklisted(
        cls,
        item: Dict[str, Any],
        title_blacklist: List[Dict[str, Any]]
    ) -> bool:
        """
        检查商品标题是否在黑名单中
        
        匹配类型：
        - contains: 包含关键字（默认）
        - equals: 精确匹配
        - regex: 正则表达式
        """
        item_title = item.get('title', '')
        if not item_title:
            return False
        
        for blacklisted in title_blacklist:
            keyword = blacklisted['keyword']
            match_type = blacklisted.get('match_type', 'contains')
            
            try:
                if match_type == 'equals':
                    # 精确匹配
                    if item_title == keyword:
                        return True
                elif match_type == 'regex':
                    # 正则匹配
                    if re.search(keyword, item_title):
                        return True
                else:
                    # 包含匹配（默认）
                    if keyword in item_title:
                        return True
            except Exception as e:
                logger.warning(f"标题黑名单匹配错误: {keyword}, {e}")
                continue
        
        return False
    
    @classmethod
    async def check_and_mark_new_items(
        cls,
        db: AsyncSession,
        search_results: List[Dict[str, Any]],
        search_keyword: str
    ) -> List[Dict[str, Any]]:
        """
        检查并标记新商品
        
        逻辑：
        1. 按发布时间或position排序（最新在前）
        2. 检查数据库中是否存在该商品
        3. 如果不存在，标记为新商品并保存
        4. 返回带有 is_new 标志的结果列表
        
        Args:
            db: 数据库会话
            search_results: 搜索结果列表
            search_keyword: 搜索关键词
            
        Returns:
            标记了新商品的搜索结果
        """
        if not search_results:
            return []
        
        # 1. 排序：按 publish_time 降序（最新在前），如果没有则按 position 升序
        sorted_results = sorted(
            search_results,
            key=lambda x: (
                -(x.get('publish_time', 0) or 0),  # publish_time 降序（负号）
                x.get('position', 999999)  # position 升序（作为次要排序）
            )
        )
        
        marked_results = []
        new_items_count = 0
        
        for item in sorted_results:
            item_id = item.get('item_id') or item.get('id')
            if not item_id:
                logger.warning(f"商品缺少ID: {item}")
                continue
            
            # 2. 检查数据库中是否存在
            query = select(SearchRecord).where(
                SearchRecord.item_id == item_id,
                SearchRecord.del_flag == '0'
            )
            result = await db.execute(query)
            existing_record = result.scalar_one_or_none()
            
            if existing_record:
                # 已存在，更新最后发现时间
                existing_record.last_found_time = datetime.now()
                existing_record.is_new = False  # 不再是新商品
                item['is_new'] = False
            else:
                # 3. 不存在，创建新记录
                new_record = SearchRecord(
                    item_id=item_id,
                    title=item.get('title'),
                    price=item.get('price'),
                    seller_id=item.get('seller_id'),
                    seller_nick=item.get('seller_nick'),
                    location=item.get('location'),
                    publish_time=item.get('publish_time'),
                    position=item.get('position'),
                    image_url=item.get('image_url'),
                    search_keyword=search_keyword,
                    is_new=True,
                    del_flag='0'
                )
                db.add(new_record)
                item['is_new'] = True
                new_items_count += 1
            
            marked_results.append(item)
        
        # 提交更改
        try:
            await db.commit()
            if new_items_count > 0:
                logger.info(f"发现 {new_items_count} 个新商品")
        except Exception as e:
            logger.error(f"保存搜索记录失败: {e}")
            await db.rollback()
        
        return marked_results


from datetime import datetime

